﻿using Newtonsoft.Json;
using Org.BouncyCastle.Asn1.Cmp;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Zocono.Infrastructure.Common;
using Zocono.WCS.Domain.DomainRepository;
using Zocono.WCS.Domain.ElevatorManage;
using Zocono.WCS.Domain.EntityInfo;
using Zocono.WCS.Domain.LogDomain;
using Zocono.WCS.Domain.PlcBytesObject;
using Zocono.WCS.Domain.PlcConnectPoolDomain;
using Zocono.WCS.Domain.ProcessModuleDomain;
using Zocono.WCS.Infrastructure.ApllicationDto.Enums;
using Zocono.WCS.Infrastructure.PlcCommon;
using Zocono.WCS.WMSApiDomain.WebApi;

namespace Zocono.WCS.Domain.EquipmentProcessDomain.PlanarGeneralMessage
{
    /// <summary>
    /// 提升机入口交互 判断目标位置的提升机出口是否空闲
    /// </summary>
    public class ArriveDDDService : IPlanarGeneralPlcActionProcessService
    {
        private readonly IRedisHelper _IRedisHelper;
        private readonly IElevatorJudgeInfoRepository _IElevatorJudgeInfoRepository;
        private readonly IPlcConnectionPool _PlcConnectionPool;
        private readonly IWorkTaskInfoRepository _WorkTaskInfoRepository;
        private readonly IPlcWriteDbInfoRepository _PlcWriteDbInfoRepository;
        private readonly IPlcReadDbInfoRepository _PlcReadeDbInfoRepository;
        private readonly IPlcConnectionInfoRepository _PlcConnectionInfoRepository;
        private readonly IElevatorInfoRepository _IElevatorInfoRepository;
        private readonly IPlcConnectionStateInfoRepository _IPlcConnectionStateInfoRepository;
        private readonly IRunLogInfoService _IRunLogInfoService;
        private readonly IElevatorMasterInfoRepository _IElevatorMasterInfoRepository;

        private readonly ILogUtil _logUtil;
        public ArriveDDDService(IRedisHelper iRedisHelper, IElevatorJudgeInfoRepository iElevatorJudgeInfoRepository
            , IElevatorMasterInfoRepository iElevatorMasterInfoRepository
            , IPlcConnectionPool plcConnectionPool
            , IWorkTaskInfoRepository workTaskInfoRepository
            , IPlcWriteDbInfoRepository plcWriteDbInfoRepository
            , IPlcConnectionInfoRepository plcConnectionInfoRepository
            , IElevatorInfoRepository elevatorInfoRepository
            , IPlcConnectionStateInfoRepository plcConnectionStateInfoRepository
            , IPlcReadDbInfoRepository plcReadDbInfoRepository
            , IRunLogInfoService iRunLogInfoService
            , ILogUtil logUtil)
        {
            _IRedisHelper = iRedisHelper;
            _IElevatorJudgeInfoRepository = iElevatorJudgeInfoRepository;
            _PlcConnectionPool = plcConnectionPool;
            _WorkTaskInfoRepository = workTaskInfoRepository;
            _PlcWriteDbInfoRepository = plcWriteDbInfoRepository;
            _PlcConnectionInfoRepository = plcConnectionInfoRepository;
            _IElevatorInfoRepository = elevatorInfoRepository;
            _IPlcConnectionStateInfoRepository = plcConnectionStateInfoRepository;
            _PlcReadeDbInfoRepository = plcReadDbInfoRepository;
            _IRunLogInfoService = iRunLogInfoService;
            _logUtil = logUtil;
            _IElevatorMasterInfoRepository = iElevatorMasterInfoRepository;
        }

        public async Task ProcessActionMessageAsync(BytesObjectBase plcActionMessage, BytesObjectBase wcsActionMessage, EquipmentDbObject planarEquipmentDbObject/*, BytesObjectBase plcStateMassge*/)
        {
            var plcMessage = plcActionMessage as PlanarGeneralPlcActionBO;//Plc的动作报文
            var wcsMessage = wcsActionMessage as PlanarGeneralWcsActionBO;//Wcs的动作报文
            //var plcStateBo = plcStateMassge as PlcOnLineStateBO;//Plc在线离线报文 没有设备信息
            plcMessage.PalletBarcode = plcMessage.PalletBarcode.Trim();
            PlanarGeneralWriteWcsAction writeBo = null;//写入Plc的报文
            PlcConnectionS7 plcConn = _PlcConnectionPool.S7GetWritePlcConnection(plcMessage.PlcConnectionID);//plc写入连接（不锁定）


            RunLogInfo runLogInfo = new()
            {
                ContainerBarcode = plcMessage.PalletBarcode,
                EquipmentCode = plcMessage.EquipmentCode,
                RunType = "跨楼层",

                RunLog = "提升机入口任务开始"
            };
            //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);

            //1. 验证plc是否在线
            var plcIPStates = await _IPlcConnectionStateInfoRepository.GetFirstAsync(l => l.PlcConnectionID == plcMessage.PlcConnectionID && l.Connected == true);
            if (plcIPStates == null)
            {
                runLogInfo.RunLog = $"{plcConn.IP}plc已离线";
                //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                _logUtil.Error($"到提升机入口：【{plcMessage.EquipmentCode}】{runLogInfo.RunLog}");
                return;
            }

            if (plcMessage.AlrmCode != 0)
            {
                runLogInfo.RunLog = $"报警,报警代码：{plcMessage.AlrmCode}";
                //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                _logUtil.Error($"到提升机入口：【{plcMessage.EquipmentCode}】{runLogInfo.RunLog}");
                return;
            }
            #region plc写入连接获取&写入报文构建
            //Plc连接Id
            long plcId = wcsMessage.PlcConnectionID;
            //写入plc的报文配置获取
            var objectType = typeof(PlanarGeneralWriteWcsAction).Name;
            var writeConfig = await _PlcWriteDbInfoRepository.GetFirstAsync(s => s.EquipmentCode == plcMessage.EquipmentCode && s.ObjectType == objectType);
            if (writeConfig == null)
            {
                runLogInfo.RunLog = $"获取PLC写入配置失败";
                //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                _logUtil.Error($"到提升机入口：【{plcMessage.EquipmentCode}】{runLogInfo.RunLog}");
                return;
            }

            //构建写入报文
            writeBo = new PlanarGeneralWriteWcsAction(
                writeConfig.PlcConnectionId,
                writeConfig.ID,
                writeConfig.DbCode,
                writeConfig.DbStart,
                objectType,
                //writeConfig.EquipmentCode.ToInt32(),
                plcMessage.EquipmentCode.ToInt32(),
                plcMessage.ActionType,
                plcMessage.ToEquipmentCode,
                taskCode: plcMessage.TaskCode,
                palletBarcode: plcMessage.PalletBarcode,
                plcMessage.PalletType,
                alrmCode: plcMessage.AlrmCode);

            if (plcConn == null)
            {
                runLogInfo.RunLog = $"获取PLC连接失败";
                //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                _logUtil.Error($"到提升机入口：【{plcMessage.EquipmentCode}】{runLogInfo.RunLog}");
                return;
            }
            #endregion

            //3. 验证wcs任务，验证wcs当前子任务
            var exp = Expressionable.Create<WorkTaskInfo>();
            exp.AndIF(plcMessage.TaskCode > 0, it => it.TaskCode == plcMessage.TaskCode);
            exp.AndIF(true, it => it.PalletCode == plcMessage.PalletBarcode && it.TaskState == EnumTaskState.Executing);
            var task = await _WorkTaskInfoRepository.GetFirstAsync(exp.ToExpression());
            if (task == null)
            {
                runLogInfo.RunLog = $"任务号({plcMessage.TaskCode})执行中的任务数据未查到";
                //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                _logUtil.Error($"到提升机入口：【{plcMessage.EquipmentCode}】{runLogInfo.RunLog}");

                writeBo.ActionType = 99;
                writeBo.AlrmCode = 7;
                var writeflag = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
                //if (writeflag == false)
                //{
                //    runLogInfo.RunLog = $"无任务报警：设备编号{writeBo.EquipmentCode})写入报文失败";
                //    //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                //    _logUtil.Error($"到达十字口：【{plcMessage.EquipmentCode}】{runLogInfo.RunLog}");
                //}
                //else
                //{
                //    runLogInfo.RunLog = $"无任务报警：设备编号{writeBo.EquipmentCode})写入报文成功";
                //    await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                //}
                return;
            }

            ////获取托盘类型 TODO新的托盘类型接口和写入  20240510 先注释现场环境暂时不支持这样修改
            //Zocono.WCS.WMSApiDomain.WebApi.HeaderResult<int> palletTypeInfo = await WCSMessageWithWMSApi.WCSGetPallentTypeAsync(plcMessage.PalletBarcode, plcMessage.EquipmentCode);

            //if (!palletTypeInfo.IsSucceed)
            //{
            //    runLogInfo.RunLog = $"请求托盘【{plcMessage.PalletBarcode}】类型失败！请查看接口信息！";
            //    //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
            //    _logUtil.Error($"到达十字口：【{plcMessage.EquipmentCode}】{runLogInfo.RunLog}");
            //    return;
            //}

            //var palletAB = task.PalletCode.Substring(1, 1);
            //if (palletAB == "A")
            //{
            //    if (palletTypeInfo.Result == 1)
            //    {
            //        writeBo.PalletType = 4;
            //    }
            //    else
            //    {
            //        writeBo.PalletType = 2;
            //    }
            //}
            //else if (palletAB == "B")
            //{
            //    if (palletTypeInfo.Result == 1)
            //    {
            //        writeBo.PalletType = 3;
            //    }
            //    else
            //    {
            //        writeBo.PalletType = 1;
            //    }
            //}
            //else
            //{
            //    if (palletTypeInfo.Result == 1)
            //    {
            //        writeBo.PalletType = 0;
            //    }
            //    else
            //    {
            //        writeBo.PalletType = 0;
            //    }
            //}

            //托盘类型
            switch (task.PalletCode.Substring(1, 1))
            {
                case "A":
                    writeBo.PalletType = 2;
                    break;
                case "B":
                    writeBo.PalletType = 1;
                    break;
                case "C":
                    writeBo.PalletType = 3;
                    break;
            }

            var routeDetailExp = Expressionable.Create<RouteDetailInfo>();
            routeDetailExp.AndIF(true, l => l.ID == task.CurrentRounteDetailID);
            var routeDetail = await _WorkTaskInfoRepository.AsSugarClient()
                .Queryable<RouteDetailInfo>()
                .Where(routeDetailExp.ToExpression())
                .Select(l => l)
                .FirstAsync();

            if (routeDetail == null)
            {
                runLogInfo.RunLog = $"巷道路径详情配置信息起始工位{task.WmsFromStation}目标工位{task.WmsToStation}获取设备路径失败";
                //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                _logUtil.Error($"到提升机入口：【{plcMessage.EquipmentCode}】{runLogInfo.RunLog}");
                return;
            }


            //获取任务的目标位置，判断提升机和提升机出口工位是否空闲
            //目标位置 task.CurrentToEquipment
            //入机台
            PlcReadDbInfo plcConfigPU = new();
            //出机台
            PlcReadDbInfo plcConfigDO = new();
            //提升机
            PlcReadDbInfo plcConfigEle = new();
            //获取所有的读DB配置数据
            var readPlcDBConfigInfo = await _PlcReadeDbInfoRepository.GetListAsync();
            try
            {
                //入机台plc读配置
                plcConfigPU = readPlcDBConfigInfo.Find(l => l.EquipmentCode == plcMessage.EquipmentCode);
                //判断是否为空
                if (plcConfigPU == null)
                {
                    writeBo.ActionType = 99;
                    //如果找不到则报警了
                    runLogInfo.RunLog = $"提升机入口【{plcMessage.EquipmentCode}】入机台没有找到配置数据！";
                    _logUtil.Error(runLogInfo.RunLog);
                    await WriteDBToPlcEle(task, writeBo, plcMessage, plcConn, runLogInfo);
                    return;
                }
            }
            catch (Exception ex)
            {
                _logUtil.Error($"入机台plc读配置失败，对应对象名plcConfigPU，捕获异常错误信息：{ex.Message}");
                throw;
            }
            try
            {
                //提升机plc读配置
                var EleEquipmentCode = readPlcDBConfigInfo.Find(l => l.EquipmentCode == plcConfigPU.PlcName).PlcName;
                plcConfigEle = readPlcDBConfigInfo.Find(l => l.EquipmentCode == EleEquipmentCode);
                //判断是否为空
                if (plcConfigEle == null)
                {
                    writeBo.ActionType = 99;
                    writeBo.AlrmCode = 151;
                    //如果找不到则报警了
                    runLogInfo.RunLog = $"提升机入口【{plcMessage.EquipmentCode}】对应提升机【{EleEquipmentCode}】没有找到读DB配置数据！";
                    _logUtil.Error(runLogInfo.RunLog);
                    await WriteDBToPlcEle(task, writeBo, plcMessage, plcConn, runLogInfo);
                    return;
                }

            }
            catch (Exception e)
            {
                _logUtil.Error($"提升机plc读配置失败，对应对象名plcConfigEle，捕获异常错误信息：{e.Message}");
                throw;
            }
            try
            {
                //出机台plc读配置
                if (plcMessage.ToEquipmentCode.ToString().Substring(0, 1) == "1")
                {
                    plcConfigDO = readPlcDBConfigInfo.Find(l => l.PlcName == $"DO{plcConfigEle.EquipmentCode}" && l.EquipmentCode.Contains("130"));//await 
                }
                else
                {
                    plcConfigDO = readPlcDBConfigInfo.Find(l => l.PlcName == $"DO{plcConfigEle.EquipmentCode}" && l.EquipmentCode.Contains(task.CurrentToEquipment.Substring(0, 3)));
                }
                //判断是否为空
                if (plcConfigDO == null)
                {
                    writeBo.ActionType = 99;
                    //如果找不到则报警了
                    runLogInfo.RunLog = $"提升机入口【{plcMessage.EquipmentCode}】对应提升机出口没有找到读DB配置数据！";
                    _logUtil.Error(runLogInfo.RunLog);
                    await WriteDBToPlcEle(task, writeBo, plcMessage, plcConn, runLogInfo);
                    return;
                }
            }
            catch (Exception ex)
            {
                _logUtil.Error($"出机台plc读配置失败，对应对象名plcConfigDO，捕获异常错误信息：{ex.Message}");
                throw;
            }

            _logUtil.Debug("提升机入料口业务数据：入料口："+ plcConfigPU.EquipmentCode);
            _logUtil.Debug("提升机入料口业务数据：出料口："+ plcConfigDO.EquipmentCode);
            _logUtil.Debug("提升机入料口业务数据：提升机："+ plcConfigEle.EquipmentCode);

            //读取提升机配置
            //获取提升机连接对象
            PlcConnectionS7 plcElevatorConn = _PlcConnectionPool.S7GetWritePlcConnection(plcConfigEle.PlcConnectionID);
            if (plcElevatorConn == null)
            {
                writeBo.ActionType = 99;
                writeBo.AlrmCode = 151;
                //如果找不到则报警了
                runLogInfo.RunLog = $"提升机入口【{plcMessage.EquipmentCode}】对应提升机【{plcConfigEle.EquipmentCode}】没有找到连接池对象！";
                _logUtil.Error(runLogInfo.RunLog);
                await WriteDBToPlcEle(task, writeBo, plcMessage, plcConn, runLogInfo);
                return;
            }
            //读取数据
            byte[] byteCurrentElevator = await plcElevatorConn.ReadDbAsync(plcConfigEle.DbCode, plcConfigEle.DbStart, plcConfigEle.DbLength);
            if (byteCurrentElevator == null)
            {
                writeBo.ActionType = 99;
                writeBo.AlrmCode = 152;
                //如果找不到则报警了
                runLogInfo.RunLog = $"提升机入口【{plcMessage.EquipmentCode}】对应提升机【{plcConfigEle.EquipmentCode}】读取提升机DB数据失败！";
                _logUtil.Error(runLogInfo.RunLog);
                await WriteDBToPlcEle(task, writeBo, plcMessage, plcConn, runLogInfo);
                return;
            }
            //序列化报文  当前提升机
            ElevatorGeneralPlcActionBO plcActionBOCurrentElevator = new();
            plcActionBOCurrentElevator.Serialize(plcConfigEle.PlcConnectionID, plcConfigEle.ID, plcConfigEle.DbStart, plcConfigEle.DbLength, plcConfigEle.DbStart, plcConfigEle.DbLength, "ElevatorGeneralPlcActionBO", plcConfigEle.EquipmentCode, byteCurrentElevator);//主要是bytes转化成明文
                                                                                                                                                                                                                                            //提升机忙  手动 报警状态 都不分配过去
            if (plcActionBOCurrentElevator.Busy || !plcActionBOCurrentElevator.Auto || plcActionBOCurrentElevator.LiftAlrm)
            {
                writeBo.ActionType = 99;
                runLogInfo.RunLog = $"提升机入口【{plcMessage.EquipmentCode}】对应提升【{plcConfigEle.EquipmentCode}】状态忙或者手动或者报警！";
                _logUtil.Error(runLogInfo.RunLog);
                await WriteDBToPlcEle(task, writeBo, plcMessage, plcConn, runLogInfo);
                return;
            }

            //获取提升机出口连接对象
            PlcConnectionS7 plcElevatorTagPuConn = _PlcConnectionPool.S7GetWritePlcConnection(plcConfigDO.PlcConnectionID);
            if (plcElevatorTagPuConn == null)
            {
                writeBo.ActionType = 99;
                writeBo.AlrmCode = 154;
                //如果找不到则报警了
                runLogInfo.RunLog = $"提升机入口【{plcMessage.EquipmentCode}】对应提升机【{plcConfigEle.EquipmentCode}】读取提升机出口【{plcConfigDO.EquipmentCode}】连接配置失败！";
                _logUtil.Error(runLogInfo.RunLog);
                await WriteDBToPlcEle(task, writeBo, plcMessage, plcConn, runLogInfo);
                return;
            }
            //读取数据
            byte[] byteCurrentElevatorTagPu = await plcElevatorTagPuConn.ReadDbAsync(plcConfigDO.DbCode, plcConfigDO.DbStart, plcConfigDO.DbLength);
            if (byteCurrentElevatorTagPu == null)
            {
                writeBo.ActionType = 99;
                writeBo.AlrmCode = 155;
                //如果找不到则报警了
                runLogInfo.RunLog = $"提升机入口【{plcMessage.EquipmentCode}】对应提升机【{plcConfigEle.EquipmentCode}】读取提升机出口【{plcConfigDO.EquipmentCode}】DB数据失败！";
                _logUtil.Error(runLogInfo.RunLog);
                await WriteDBToPlcEle(task, writeBo, plcMessage, plcConn, runLogInfo);
                return;
            }
            PlanarGeneralPlcActionBO plcActionCurrentElevatorTagPU = new();
            plcActionCurrentElevatorTagPU.Serialize(plcConfigDO.PlcConnectionID, plcConfigDO.ID, plcConfigDO.DbStart, plcConfigDO.DbLength, plcConfigDO.DbStart, plcConfigDO.DbLength, "PlanarGeneralPlcActionBO", plcConfigDO.EquipmentCode, byteCurrentElevatorTagPu);//主要是bytes转化成明文
            if (plcActionCurrentElevatorTagPU.PalletBarcode.Trim() != "")
            {

                writeBo.ActionType = 99;
                runLogInfo.RunLog = $"提升机入口【{plcMessage.EquipmentCode}】对【{plcConfigEle.EquipmentCode}】出口【{plcConfigDO.EquipmentCode}】有料在！！";
                _logUtil.Error(runLogInfo.RunLog);
                await WriteDBToPlcEle(task, writeBo, plcMessage, plcConn, runLogInfo);
                return;
            }
            else
            {
                writeBo.ActionType = 10;
                await WriteDBToPlcEle(task, writeBo, plcMessage, plcConn, runLogInfo);
                return;
            }

            


        }




        /// <summary>
        /// 写入PLC方法
        /// </summary>
        /// <param name="task"></param>
        /// <param name="writeBo"></param>
        /// <param name="plcMessage"></param>
        /// <param name="plcConn"></param>
        /// <param name="runLogInfo"></param>
        /// <returns></returns>
        public async Task WriteDBToPlcEle(WorkTaskInfo task, PlanarGeneralWriteWcsAction writeBo, PlanarGeneralPlcActionBO plcMessage, PlcConnectionS7 plcConn, RunLogInfo runLogInfo)
        {
            //写入正常报文
            writeBo.TaskCode = task.TaskCode;
            writeBo.PalletBarcode = task.PalletCode;
            writeBo.ToEquipmentCode = task.CurrentToEquipment.ToInt32();
            var writeBl = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());

            if (!writeBl)
            {
                runLogInfo.RunLog = $"提升机入口{plcMessage.EquipmentCode}申请入提升机写入正常报文失败，报文内容：{JsonConvert.SerializeObject(writeBo)}";
                await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
            }
            else
            {
                if (writeBo.ActionType == 10)
                {
                    runLogInfo.RunLog = $"提升机入口 {plcMessage.EquipmentCode}申请入提升机允许进入写入正常报文成功，报文内容：{JsonConvert.SerializeObject(writeBo)}";
                    await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                }
                //else if (writeBo.ActionType == 12)
                //{
                //    runLogInfo.RunLog = $"十字口{plcMessage.EquipmentCode}申请入提升机不允许进入原因：【{runLogInfo.RunLog}】;写入正常报文成功，报文内容：{JsonConvert.SerializeObject(writeBo)}";
                //    await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                //}
                else if (writeBo.ActionType == 99)
                {
                    runLogInfo.RunLog = $"提升机入口{plcMessage.EquipmentCode}申请入提升机进入报错原因：【{runLogInfo.RunLog}】;写入正常报文成功，报文内容：{JsonConvert.SerializeObject(writeBo)}";
                    await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                }
            }
        }
    }
}
